package by.gravity.drive_track;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import by.gravity.common.CommonFragmentActivity;
import by.gravity.common.utils.GetSystemService;
import by.gravity.common.utils.ImageUtil;
import by.gravity.common.utils.MapUtil;
import by.gravity.common.utils.ResourceUtil;
import by.gravity.drive_track.fragments.FavoritePointFragment;
import by.gravity.drive_track.fragments.MarkerActionDialogFragment;
import by.gravity.drive_track.fragments.RouteFragment;
import by.gravity.drive_track.fragments.RouteFragment.SELECTED_MODE;
import by.gravity.drive_track.model.Favorite;
import by.gravity.drive_track.provider.DriveNTrackProvider;
import by.gravity.drive_track.provider.listeners.OnDirectionCompleteListener;
import by.gravity.drive_track.ui.appmessage.AppMsg;

import com.flurry.android.FlurryAgent;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.gson.Gson;

public class MainActivity extends CommonFragmentActivity implements AppIntents {

	private static final String TAG = MainActivity.class.getSimpleName();

	private GoogleMap mMap;

	private LocationManager mLocationManager;

	private List<Polyline> mPolyLineList;

	private HashMap<Integer, Marker> mMarkerMap;

	protected DriveNTrackProvider mProvider;

	private boolean isSelectPointMode = false;

	private int number;

	private boolean isIntenFromDialog = false;

	private LatLng mStartPoint;

	private LatLng mFinishPoint;

	private SELECTED_MODE mSelectedMode = SELECTED_MODE.CAR;

	private List<Marker> mSelectedMarkerList;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.a_main);
		mProvider = DriveNTrackProvider.get(this);

		mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
		mLocationManager = (LocationManager) GetSystemService.get(this, Context.LOCATION_SERVICE);
		mPolyLineList = new ArrayList<Polyline>();
		mMarkerMap = new HashMap<Integer, Marker>();
		mSelectedMarkerList = new ArrayList<Marker>();

		initMap();

		mMap.setOnMapLongClickListener(new OnMapLongClickListener() {

			@Override
			public void onMapLongClick(LatLng point) {
				if (isSelectPointMode) {
					saveMarker(point, number);
					onPointSelected();
				}

			}
		});

		mMap.setOnMarkerClickListener(new OnMarkerClickListener() {

			@Override
			public boolean onMarkerClick(Marker marker) {
				Favorite favorite = new Favorite(marker.getPosition().hashCode(), System.currentTimeMillis(), marker
						.getPosition());

				MarkerActionDialogFragment fragment = new MarkerActionDialogFragment();
				Bundle bundle = new Bundle();
				bundle.putString(ARG_FAVORITE_POINT, new Gson().toJson(favorite));
				fragment.setArguments(bundle);
				fragment.show(getSupportFragmentManager(), MarkerActionDialogFragment.TAG);
				return false;
			}
		});

		Button test = ((Button) findViewById(R.id.test));
		test.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View paramView) {
				clearPoints();
				showRouteFragment();
			}
		});

	}

	private Marker getMarker(LatLng position, int number) {
		MarkerOptions markerOptions = new MarkerOptions();
		markerOptions.position(position);
		markerOptions.icon(getMarket(number));
		return mMap.addMarker(markerOptions);
	}

	private void saveMarker(LatLng point, int number) {
		if (number == -2) {
			mStartPoint = point;
		} else if (number == -1) {
			mFinishPoint = point;
		}

		Marker marker = getMarker(point, number);

		if (mMarkerMap.containsKey(number)) {
			mMarkerMap.get(number).remove();
		}
		mMarkerMap.put(number, marker);

	}

	protected void onPointSelected() {
		showRouteFragment();
		sendPointName();
		if (isIntenFromDialog) {
			isIntenFromDialog = false;
			Intent intent = new Intent(SHOW_ADD_ROUTE_DIALOG_INTENT);
			sendBroadcast(intent);
		}
	}

	protected void addNumberMarker(List<Integer> wayPointOrder) {
		for (int i = wayPointOrder.size() - 1; i >= 0; i--) {
			int number = wayPointOrder.get(i);
			if (number < mSelectedMarkerList.size()) {
				MarkerOptions options = new MarkerOptions();
				BitmapDescriptor markerIcon = getMarket(i);
				if (markerIcon != null) {
					Marker marker = mSelectedMarkerList.get(number);
					if (marker != null) {
						LatLng position = marker.getPosition();
						options.icon(markerIcon);
						options.position(position);
						mSelectedMarkerList.get(number).remove();
						mMarkerMap.put(number, mMap.addMarker(options));

					}

				}
			}
		}
	}

	protected void onSuccessRoute(List<LatLng> result, List<Integer> wayPointOrder) {
		addNumberMarker(wayPointOrder);
		MapUtil.removePolylines(mPolyLineList);
		mPolyLineList.add(mMap.addPolyline((new PolylineOptions().color(Color.BLUE).width(5)).addAll(result)));

		CameraPosition cameraPosition = new CameraPosition.Builder().target(mStartPoint)
				.zoom(mMap.getCameraPosition().zoom).build();
		mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

	}

	private BitmapDescriptor getMarket(int number) {
		if (number == -2) {
			return BitmapDescriptorFactory.fromResource(R.drawable.marker_start);
		} else if (number == -1) {
			return BitmapDescriptorFactory.fromResource(R.drawable.marker_finish);
		} else {
			int drawableID = ResourceUtil.getDrawableId(this, "marker_" + (number + 1));
			if (drawableID != 0) {
				Drawable drawable = getResources().getDrawable(drawableID);
				if (drawable != null) {
					return BitmapDescriptorFactory.fromBitmap(ImageUtil.convertDrawableToBitmap(drawable));
				}
			}
			return null;
		}
	}

	private void initMap() {

		mMap.setMyLocationEnabled(true);
		mMap.getUiSettings().setZoomControlsEnabled(false);
		LatLng point = getCurrentLocation();
		if (point != null) {

			mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(point, 15));
		}

	}

	private LatLng getCurrentLocation() {
		Location location = mMap.getMyLocation();
		if (location != null) {
			return new LatLng(location.getLatitude(), location.getLongitude());
		} else {
			location = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
			if (location != null) {
				return new LatLng(location.getLatitude(), location.getLongitude());
			}
		}

		return null;
	}

	protected void showRouteFragment() {
		RelativeLayout fragmentLayout = (RelativeLayout) findViewById(R.id.fragmentLyaout);
		fragmentLayout.setVisibility(View.VISIBLE);
		if (!isSelectPointMode) {
			FragmentManager manager = getSupportFragmentManager();
			FragmentTransaction transaction = manager.beginTransaction();
			transaction.add(R.id.fragmentLyaout, new RouteFragment(), RouteFragment.TAG);
			transaction.addToBackStack(RouteFragment.TAG);
			transaction.commit();
		}

		RelativeLayout layout = (RelativeLayout) findViewById(R.id.main);
		layout.setVisibility(View.INVISIBLE);

	}

	private boolean routeFragmentIsShow() {
		RelativeLayout fragmentLayout = (RelativeLayout) findViewById(R.id.fragmentLyaout);
		return fragmentLayout.getVisibility() == View.VISIBLE;
	}

	protected void sendPointName() {
		String pointName = "";
		if (number == -2) {
			pointName = String.format(getString(R.string.point), "A");
		} else if (number == -1) {
			pointName = String.format(getString(R.string.point), "B");
		} else {
			pointName = String.format(getString(R.string.point), "" + (number + 1));
		}
		sendPointName(pointName);
	}

	protected void sendPointName(String pointName) {
		Intent intent = new Intent(ADD_POINT_NAME_INTENT);
		intent.putExtra(ARG_POINT_NAME, pointName);
		intent.putExtra(ARG_POINT_NUMBER, number);
		sendBroadcast(intent);
	}

	protected void hideRouteFragment() {
		if (routeFragmentVisible()) {
			RelativeLayout fragmentLayout = (RelativeLayout) findViewById(R.id.fragmentLyaout);
			fragmentLayout.setVisibility(View.INVISIBLE);

			RelativeLayout mapLayout = (RelativeLayout) findViewById(R.id.main);
			mapLayout.setVisibility(View.VISIBLE);
		}
	}

	protected boolean routeFragmentVisible() {
		RelativeLayout fragmentLayout = (RelativeLayout) findViewById(R.id.fragmentLyaout);
		return fragmentLayout.getVisibility() == View.VISIBLE;
	}

	protected void removeRouteFragment() {
		hideRouteFragment();
		Fragment fragment = getSupportFragmentManager().findFragmentByTag(RouteFragment.TAG);
		if (fragment != null) {
			FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
			transaction.remove(fragment);
			transaction.commit();
		}

	}

	private void clearPoints() {
		MapUtil.removePolylines(mPolyLineList);
		MapUtil.removeMarkers(mMarkerMap);
		mStartPoint = null;
		mFinishPoint = null;
	}

	public void onLocationClick(View view) {
		setNumberPoint(view);
		hideRouteFragment();
		isSelectPointMode = true;
		AppMsg.makeText(this, getSeletePointMessage(), AppMsg.STYLE_INFO).show();
	}

	public void onFavoriteClick(View view) {
		setNumberPoint(view);
		FavoritePointFragment favoritePointFragment = new FavoritePointFragment();
		favoritePointFragment.show(getSupportFragmentManager(), FavoritePointFragment.TAG);
	}

	private String getSeletePointMessage() {
		if (number == -2) {
			return getString(R.string.choose_start_point);
		} else if (number == -1) {
			return getString(R.string.choose_finish_point);
		} else {
			return getString(R.string.choose_add_point);
		}

	}

	public void onStartClick(View view) {
		if (mFinishPoint == null) {
			Toast.makeText(this, R.string.not_selected_finish_point, Toast.LENGTH_SHORT).show();
		} else {
			isSelectPointMode = false;
			removeRouteFragment();
			List<LatLng> point = new ArrayList<LatLng>();
			if (mStartPoint == null) {
				mStartPoint = getCurrentLocation();
				point.add(getCurrentLocation());
			} else {
				point.add(mStartPoint);
			}
			point.add(mFinishPoint);
			mSelectedMarkerList.clear();
			for (int markerKey : mMarkerMap.keySet()) {
				if (markerKey >= 0) {
					Marker marker = mMarkerMap.get(markerKey);
					point.add(marker.getPosition());
					mSelectedMarkerList.add(marker);
				}
			}

			getRoute(point);
		}
	}

	private void getRoute(List<LatLng> selectedPoints) {
		mProvider.getDirection(selectedPoints, mSelectedMode, new OnDirectionCompleteListener() {

			@Override
			public void onSuccess(List<LatLng> result, List<Integer> wayPointOrder) {
				onSuccessRoute(result, wayPointOrder);

			}

			@Override
			public void onError() {
				Log.e(TAG, "error status");

			}
		});
	}

	private void setNumberPoint(View view) {
		if (((LinearLayout) view.getParent()).getTag() != null) {
			String tag = ((LinearLayout) view.getParent()).getTag().toString();
			if (TextUtils.isDigitsOnly(tag)) {
				number = Integer.valueOf(tag);
			} else {
				number = Integer.valueOf(tag.split(DIALOG_SPLIT)[0]);
				isIntenFromDialog = true;
				Intent intent = new Intent(HIDE_ADD_ROUTE_DIALOG_INTENT);
				sendBroadcast(intent);
			}
		}

	}

	@Override
	public void onBackPressed() {
		if (isSelectPointMode) {
			if (routeFragmentIsShow()) {
				hideRouteFragment();
			} else {
				showRouteFragment();
			}
		} else {
			super.onBackPressed();
			hideRouteFragment();
		}
	}

	public void onCarModeClick(View view) {
		mSelectedMode = SELECTED_MODE.CAR;
		Intent intent = new Intent(ON_DRIVIND_MODE_CLICK_INTENT);
		sendBroadcast(intent);
	}

	public void onWalkModeClick(View view) {
		mSelectedMode = SELECTED_MODE.WALK;
		Intent intent = new Intent(ON_WALKING_MODE_CLICK_INTENT);
		sendBroadcast(intent);
	}

	@Override
	protected void addIntentFilter(IntentFilter filter) {
		filter.addAction(REMOVE_POINT_INTENT);
		filter.addAction(ON_POINT_NAME_SELECTED_INTENT);
		filter.addAction(ADD_POINT_NAME_FROM_FAVORITE_INTENT);
	}

	@Override
	protected void onBroadcastReceive(Intent intent) {
		if (intent.getAction().equals(REMOVE_POINT_INTENT)) {
			int number = intent.getIntExtra(ARG_POINT_NUMBER, -1);
			Marker marker = mMarkerMap.get(number);
			if (marker != null) {
				marker.remove();
				mMarkerMap.remove(number);
			}
		} else if (intent.getAction().equals(ON_POINT_NAME_SELECTED_INTENT)) {
			int number = intent.getIntExtra(ARG_POINT_NUMBER, 0);
			by.gravity.drive_track.model.direction.Location location = (by.gravity.drive_track.model.direction.Location) intent
					.getSerializableExtra(ARG_POINT_LOCATION);
			saveMarker(new LatLng(location.getLatitude(), location.getLongitude()), number);
		} else if (intent.getAction().equals(ADD_POINT_NAME_FROM_FAVORITE_INTENT)) {
			Favorite favorite = (Favorite) intent.getSerializableExtra(ARG_FAVORITE_POINT);
			saveMarker(favorite.getPoint(), number);
			sendPointName(favorite.getName());
		}
	}

	@Override
	protected void onStart() {
		super.onStart();
		FlurryAgent.onStartSession(this, getString(R.string.flurry_key));
	}

	@Override
	protected void onStop() {
		super.onStop();
		FlurryAgent.onEndSession(this);
	}

}
